1   /*
2    * Copyright (C) 2007 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.io;
18  
19  import static com.google.common.base.Preconditions.checkNotNull;
20  
21  import com.google.common.annotations.Beta;
22  
23  import java.io.IOException;
24  import java.io.Reader;
25  import java.nio.CharBuffer;
26  import java.util.LinkedList;
27  import java.util.Queue;
28  
29  /**
30   * A class for reading lines of text. Provides the same functionality
31   * as {@link java.io.BufferedReader#readLine()} but for all {@link Readable}
32   * objects, not just instances of {@link Reader}.
33   *
34   * @author Chris Nokleberg
35   * @since 1.0
36   */
37  @Beta
38  public final class LineReader {
39    private final Readable readable;
40    private final Reader reader;
41    private final char[] buf = new char[0x1000]; // 4K
42    private final CharBuffer cbuf = CharBuffer.wrap(buf);
43  
44    private final Queue<String> lines = new LinkedList<String>();
45    private final LineBuffer lineBuf = new LineBuffer() {
46      @Override protected void handleLine(String line, String end) {
47        lines.add(line);
48      }
49    };
50  
51    /**
52     * Creates a new instance that will read lines from the given
53     * {@code Readable} object.
54     */
55    public LineReader(Readable readable) {
56      this.readable = checkNotNull(readable);
57      this.reader = (readable instanceof Reader) ? (Reader) readable : null;
58    }
59  
60    /**
61     * Reads a line of text. A line is considered to be terminated by any
62     * one of a line feed ({@code '\n'}), a carriage return
63     * ({@code '\r'}), or a carriage return followed immediately by a linefeed
64     * ({@code "\r\n"}).
65     *
66     * @return a {@code String} containing the contents of the line, not
67     *     including any line-termination characters, or {@code null} if the
68     *     end of the stream has been reached.
69     * @throws IOException if an I/O error occurs
70     */
71    public String readLine() throws IOException {
72      while (lines.peek() == null) {
73        cbuf.clear();
74        // The default implementation of Reader#read(CharBuffer) allocates a
75        // temporary char[], so we call Reader#read(char[], int, int) instead.
76        int read = (reader != null)
77            ? reader.read(buf, 0, buf.length)
78            : readable.read(cbuf);
79        if (read == -1) {
80          lineBuf.finish();
81          break;
82        }
83        lineBuf.add(buf, 0, read);
84      }
85      return lines.poll();
86    }
87  }